/*
 * @Author: 梁青春
 * @Date: 2025-11-06 10:47:37
 * @LastEditTime: 2025-11-06 10:48:43
 * @LastEditors: 梁青春
 */
/**
 * 把 vnode 转成真实节点并打印
 * @param {import('vue').VNode} vnode
 * @param {object} opts { width, height, landscape }
 * @returns Promise
 */
import { createApp, h } from 'vue'

/**
 * 等待打印页面资源（字体、图片）加载完成，避免出现空白或丢图
 * @param {Document} doc 打印 iframe 的 document
 */
async function waitResources(doc) {
  // 等待字体就绪（Chromium 支持 document.fonts）
  try {
    if (doc.fonts && doc.fonts.ready) {
      await doc.fonts.ready
    }
  } catch (_) {
    // 字体等待失败不阻塞打印，保证稳健性
  }
  // 等待所有图片加载完成（失败不阻塞）
  const imgs = Array.from(doc.images || [])
  await Promise.all(
    imgs.map(img =>
      img.complete
        ? Promise.resolve()
        : new Promise(res => {
            img.onload = () => res()
            img.onerror = () => res()
          })
    )
  )
}

/**
 * 复制主文档中的样式到打印 iframe，确保 scoped 样式和全局样式在打印页生效
 * @param {Document} parentDoc 主文档
 * @param {HTMLHeadElement} targetHead 打印 iframe 的 head
 */
function copyStyles(parentDoc, targetHead) {
  const styleNodes = parentDoc.querySelectorAll('style, link[rel="stylesheet"]')
  styleNodes.forEach(node => {
    const clone = node.cloneNode(true)
    targetHead.appendChild(clone)
  })
}

/**
 * 生成 @page 尺寸样式，并支持横向打印
 * @param {{width?: string, height?: string, landscape?: boolean}} opts
 */
function pageSizeCss(opts = {}) {
  const w = opts.width || '210mm'
  const h = opts.height || '297mm'
  const size = opts.landscape ? `${h} ${w}` : `${w} ${h}`
  return `@page { size: ${size}; margin: 0; }`
}

export function printVNode(vnode, opts = {}) {
  return new Promise(resolve => {
    const iframe = document.createElement('iframe')
    // 使用不可见但有尺寸的隐藏策略，减少 0 尺寸导致的布局/资源问题
    Object.assign(iframe.style, {
      position: 'fixed',
      left: '-9999px',
      top: 0,
      visibility: 'hidden', // 不可见但仍参与布局
      width: opts.width || '210mm',
      height: opts.height || '297mm'
    })
    document.body.appendChild(iframe)
    const win = iframe.contentWindow
    const doc = win.document

    // 写基础结构
    doc.write(`
      <!doctype html>
      <html>
        <head>
          <meta charset="utf-8">
          <title>医院打印</title>
          <style>
            ${pageSizeCss(opts)}
            body{margin:0;font:12px/1.4 'Microsoft YaHei';color:#000}
            *{box-sizing:border-box}
            ${opts.extraCss || ''}
          </style>
        </head>
        <body><div id="app_print"></div></body>
      </html>
    `)
    doc.close()

    // 复制主文档样式到打印 iframe，解决 scoped 样式不生效的问题
    try {
      copyStyles(document, doc.head)
    } catch (_) {
      // 样式复制失败不阻塞打印
    }

    // 创建临时 Vue 实例把 vnode 渲染到 iframe
    const app = createApp({ render: () => vnode })
    app.mount(doc.getElementById('app_print'))

    // 等待资源加载完成后再触发打印，避免空白/缺图
    ;(async () => {
      await waitResources(doc)
      win.focus()
      win.print()
      setTimeout(() => {
        app.unmount()
        document.body.removeChild(iframe)
        resolve()
      }, 200)
    })()
  })
}
